package com.hanweb.utils;

import com.hanweb.FabricJavaSdkApplication;
import com.hanweb.common.IntegralContractConstant;
import lombok.extern.slf4j.Slf4j;
import org.hyperledger.fabric.gateway.*;
import org.hyperledger.fabric.sdk.Peer;

import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.InvalidKeyException;
import java.security.PrivateKey;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.EnumSet;
import java.util.Properties;

/**
 * @author Seven.Yin
 */
@Slf4j
public class ContractOprUtil {

    /**
     * 获取智能合约对象
     *
     * @return 智能合约对象操作类
     */
    public static Contract getContract() {
        Contract contract = null;
        try {
            //获取相应参数
            Properties properties = new Properties();
            InputStream inputStream = FabricJavaSdkApplication.class.getResourceAsStream(IntegralContractConstant.FABRIC_CONFIG_PROPERTIES);
            properties.load(inputStream);

            String networkConfigPath = properties.getProperty(IntegralContractConstant.NETWORK_CONFIG_PATH);
            String channelName = properties.getProperty(IntegralContractConstant.CHANNEL_NAME);
            String contractName = properties.getProperty(IntegralContractConstant.CONTRACT_NAME);
            //使用org1中的user1初始化一个网关wallet账户用于连接网络
            String certificatePath = properties.getProperty(IntegralContractConstant.CERTIFICATE_PATH);
            X509Certificate certificate = readX509Certificate(Paths.get(certificatePath));

            String privateKeyPath = properties.getProperty(IntegralContractConstant.PRIVATE_KEY_PATH);
            PrivateKey privateKey = getPrivateKey(Paths.get(privateKeyPath));

            Wallet wallet = Wallets.newInMemoryWallet();
            wallet.put(IntegralContractConstant.SIGN_PREFIX, Identities.newX509Identity(IntegralContractConstant.ORG_ONE_MSG, certificate, privateKey));

            //根据connection.json 获取Fabric网络连接对象
            Gateway.Builder builder = Gateway.createBuilder()
                    .identity(wallet, IntegralContractConstant.SIGN_PREFIX)
                    .networkConfig(Paths.get(networkConfigPath));
            //连接网关
            Gateway gateway = builder.connect();
            //获取通道
            Network network = gateway.getNetwork(channelName);
            //获取合约对象
            contract = network.getContract(contractName);

        } catch (Exception e) {

            log.error("=========================>连接Fabric网络错误!");
        }

        return contract;
    }

    /**
     * 获取交易对象
     *
     * @param method 事务函数名称
     * @return 交易对象
     */
    public static Transaction transactionOfCreate(String method) {
        Transaction transaction = null;
        try {
            //获取相应参数
            Properties properties = new Properties();
            InputStream inputStream = FabricJavaSdkApplication.class.getResourceAsStream(IntegralContractConstant.FABRIC_CONFIG_PROPERTIES);
            properties.load(inputStream);

            String networkConfigPath = properties.getProperty(IntegralContractConstant.NETWORK_CONFIG_PATH);
            String channelName = properties.getProperty(IntegralContractConstant.CHANNEL_NAME);
            String contractName = properties.getProperty(IntegralContractConstant.CONTRACT_NAME);
            //使用org1中的user1初始化一个网关wallet账户用于连接网络
            String certificatePath = properties.getProperty(IntegralContractConstant.CERTIFICATE_PATH);
            X509Certificate certificate = readX509Certificate(Paths.get(certificatePath));

            String privateKeyPath = properties.getProperty(IntegralContractConstant.PRIVATE_KEY_PATH);
            PrivateKey privateKey = getPrivateKey(Paths.get(privateKeyPath));

            Wallet wallet = Wallets.newInMemoryWallet();
            wallet.put(IntegralContractConstant.SIGN_PREFIX, Identities.newX509Identity(IntegralContractConstant.ORG_ONE_MSG, certificate, privateKey));

            //根据connection.json 获取Fabric网络连接对象
            Gateway.Builder builder = Gateway.createBuilder()
                    .identity(wallet, IntegralContractConstant.SIGN_PREFIX)
                    .networkConfig(Paths.get(networkConfigPath));
            //连接网关
            Gateway gateway = builder.connect();
            //获取通道
            Network network = gateway.getNetwork(channelName);
            //获取合约对象
            Contract contract = network.getContract(contractName);

            transaction = contract.createTransaction(method)
                    .setEndorsingPeers(network.getChannel().getPeers(EnumSet.of(Peer.PeerRole.ENDORSING_PEER)));

        } catch (Exception e) {

            log.error("=========================>连接Fabric网络错误!");
        }

        return transaction;
    }

    private static X509Certificate readX509Certificate(final Path certificatePath) throws IOException, CertificateException {
        try (Reader certificateReader = Files.newBufferedReader(certificatePath, StandardCharsets.UTF_8)) {
            return Identities.readX509Certificate(certificateReader);
        }
    }

    private static PrivateKey getPrivateKey(final Path privateKeyPath) throws IOException, InvalidKeyException {
        try (Reader privateKeyReader = Files.newBufferedReader(privateKeyPath, StandardCharsets.UTF_8)) {
            return Identities.readPrivateKey(privateKeyReader);
        }
    }
}
